#include "copycat.h"

//////////////////////////////////////////////////////////////////////////////
bool SetNodeSpan( CSent &s, CTree &tree )
{
	// [-1] [3 5] [-1] [2] 구조
	for( int i=0; i<s.align_list.GetSize(); i++ )	{
		CUString str = s.align_list.GetAt(i);
		
		CUStringList ls; ls.TokenizeByChar( str, " ", false );
		for( int j=0; j<ls.GetSize(); j++ )	{
			int align_tgt_id = atoi( ls.GetAt(j) );
			if( align_tgt_id == -1 ) continue;

			CNode *n = tree.GetNodeByLexID( i );
			if( n == NULL )	{
				fprintf( stdout, "%d !!!!\n", i );
				continue;
			}

			n->AddAlign( align_tgt_id );

			if( n->span_from == NULL_NUM || n->span_to == NULL_NUM )	{
				n->span_from = align_tgt_id;
				n->span_to = align_tgt_id;
			}
			else {
				if( align_tgt_id  < n->span_from  )		n->span_from = align_tgt_id;
				if( n->span_to     < align_tgt_id )		n->span_to   = align_tgt_id;
			}
		}
	}

	tree.UpdateSpan();
	tree.UpdateTgtAlign();

	return true;
}



void ExtractInsRule( CSent &sent, CTree &tree, CGiza &giza, FILE *fp )
{
	int ls[NUM_MAX_NODE];
	int s=-1;

	tree.GetTraverseList( ls, s );
	for( int i=0; i<s; i++ )	{
		CNode &n = tree.node[ ls[i] ];
		if( n.IsTerminal() )	continue;

		// skip condition
		bool all_aligned=true;
		for( int j=0; j<n.num_child; j++ )	{
			CNode &c = tree.node[ n.child[j] ];
			if( c.span_from == NULL_NUM || c.span_to == NULL_NUM )	{
				all_aligned=false;
				break;
			}
		}
		if( all_aligned == false )	continue;

		// init
		int un_stack[NUM_MAX_NODE];
		for( int j=0; j<NUM_MAX_NODE; j++ )	un_stack[j] = NULL_NUM;

		// store span ranges of child nodes
		CUString before = n.label;
		for( int j=0; j<n.num_child; j++ )	{
			CNode &c = tree.node[ n.child[j] ];
			char buf[1024]; sprintf( buf, " [%s]", c.label.GetStr() ); before += buf;
			for( int k=c.span_from; k<=c.span_to; k++ )	{
				un_stack[k] = c.id;
			}
		}
		/*
		for( int j=0; j<n.num_child; j++ )	{
			CNode &c = tree.node[ n.child[j] ];
			char buf[1024]; sprintf( buf, " [%s %d~%d]", c.label.GetStr(), c.span_from, c.span_to ); before += buf;
			for( int k=c.span_from; k<=c.span_to; k++ )	{
				char buf[1024];
				sprintf( buf, " %s", sent.tgt_tok_list.GetAt(k) );
				before += buf;
			}
		}
		*/

		// detect missed (insertable) target words
		CUString result;
		int prev_idx = NULL_NUM;
		for( int j=n.span_from; j<=n.span_to; j++ )	{
			if( un_stack[j] == NULL_NUM )	{
				result += CUString(" @");
				result += sent.tgt_tok_list.GetAt(j);
			}
			else	{
				if( un_stack[j] != prev_idx )	{
					char buf[1024];
					sprintf( buf, " {%s}", tree.node[ un_stack[j] ].label.GetStr() );
					result += buf;
					prev_idx = un_stack[j];
				}
			}
		}
		result.Trim(" ");

		// print
//		if( before.Find( "S [NP] [VP]" ) == 0 )	
		{
			fprintf( fp, "%s\t%s\n", before.GetStr(), result.GetStr() );

			/*
			fprintf( fp, "%s", n.label.GetStr() );
			for( int j=n.span_from; j<=n.span_to; j++ )	{
				CNode &c = tree.node[ n.child[j] ];
				fprintf( fp, " [%s %d~%d]", c.label.GetStr(), c.span_from, c.span_to );
			}
			fprintf( fp, "\n%s\n", sent.parse.GetStr() );
			*/
		}
		/*
		if( n.label != par_label )	continue;
		if( n.num_child != 2 )	continue;

		CNode &c1 = tree.node[ n.child[0] ];
		CNode &c2 = tree.node[ n.child[1] ];

		if( c1.label != c1_label )	continue;
		if( c2.label != c2_label )	continue;

		int tmp = n.child[0];
		n.child[0] = n.child[1];
		n.child[1] = tmp;
		*/
	}

}


int main( int argc, char *argv[] )
{
	if( argc != 3 )	{
		fprintf( stderr, "usage: %s  src-prefix giza(union)\n", argv[0] );
		return 1;
	}

	CUString fn = CUString( argv[1] ) + CUString(".parse" );
	CUTextFile parse_file( fn, "r" );
	if( parse_file.CheckOpen() == false )	return 1;

	CUString fn2 = CUString( argv[1] ) + CUString("-hrule.parse" );
	CUTextFile out_file( fn2, "w" );

	CUString fn3 = CUString( argv[1] ) + CUString("-hrule.SP" );
	CUTextFile out_file2( fn3, "w" );

	CGiza giza;
	if( giza.Open( argv[2] ) == false )	return false;
	
	int num_sent = 0;
	while(1)	{
		CUString line;
		if( parse_file.ReadLine( line ) == false )	break;
		line.Replace("\r", "" );
		num_sent++;

		if( num_sent % 1000 == 0 )		fprintf( stderr, "." );
		else if( num_sent % 10000 == 0 )		fprintf( stderr, "\n" );

		if( line.Find("(ROOT (") == 0 )	{
			line = line.SubStr( 6, line.GetLength()-1);
		}


		CSent s;
		s.id = num_sent;
		s.parse = line;
		// load word alignment
		if( giza.ReadSent() == false )	{
			fprintf( stderr, "Fail to read giza\n" );
			return false;
		}
		s.src_tok_list.Clear();
		for( int i=1; i<giza.src.tok_list.GetSize(); i++ )	{
			s.src_tok_list.PushBack( giza.src.tok_list.GetAt(i) );
		}

		s.align_list.Clear();
		for( int i=1; i<giza.align.align_list.GetSize(); i++ )	{
			CUString str = giza.align.align_list.GetAt(i);
			int align = -1;
			if( str != "" )	align = atoi( str.GetStr() )-1;
			char tmp[16]; sprintf( tmp, "%d", align );
			s.align_list.PushBack( tmp );
		}

		s.tgt_tok_list.Clear();
		for( int i=0; i<giza.tgt.tok_list.GetSize(); i++ )	{
			s.tgt_tok_list.PushBack( giza.tgt.tok_list.GetAt(i) );
		}

		// load tree
		CTree tree;
		if( tree.LoadTree( line ) == false )	return 1;
		SetNodeSpan( s, tree);




		// ins rules
		ExtractInsRule( s, tree, giza, out_file.GetFP() );

		// print
		CUString str; tree.PrintStrRecurr( 0, str); str.Trim(" ");
//		fprintf( out_file.GetFP(), "%s\n", str.GetStr() );
		tree.PrintLexPos2File( out_file2 );
	}

	fprintf( stderr, "\n" );
	fprintf( stderr, "%d sents\n", num_sent );


	return 0;
}

